#include<stdio.h>
#include<sys/mman.h>
#include<sys/ipc.h>

int* critical;

int createSem() {
	return semget((key_t)1000, 2, IPC_CREAT | 0600);
}

void initSignal(int semid, int index, int value) {
	semctl(semid, index, SETVAL, value);
}

void make_critical() {
	critical = mmap(NULL, 2 * sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
	critical[0] = 0;
	critical[1] = 0;
}

void semWait(int semid, int index) {
	struct sembuf sem_buf;
	sem_buf.sem_num = index;
	sem_buf.sem_op = -1;
	sem_buf.sem_flg = SEM_UNDO;
	semop(semid, &sem_buf, 1);
}

void semSignal(int semid, int index) {
	struct sembuf sem_buf;
	sem_buf.sem_num = index;
	sem_buf.sem_op = 1;
	sem_buf.sem_flg = SEM_UNDO;
	semop(semid, &sem_buf, 1);
}

void reader(int semid, int readerid){
	while (1) {
		int i;
		semWait(semid, 1);
		critical[0]++;
		if (critical[0] == 1) semWait(semid, 0);
		semSignal(semid, 1);

		printf("ReadFork%d excute: Read  %d.\n", readerid, critical[1]);
		sleep(1);

		semWait(semid, 1);
		critical[0]--;
		if (critical[0] == 0) semSignal(semid, 0);
		semSignal(semid, 1);
	}
}

void writer(int semid) {
	while (1) {
		semWait(semid, 0);
		critical[1] = rand() % 10;
		printf("WriterFork excute: Write  %d.\n",critical[1]);
		sleep(1);
		semSignal(semid, 0);
	}
}

int main() {
	int semid = createSem();
	initSignal(semid, 0, 1);
	initSignal(semid, 1, 1);
	make_critical();

	pid_t child1 = fork();
	if (child1 < 0) {
		printf("fail");
	}
	else if (child1 == 0)
	{
		reader(semid, 1);
	}
	else
	{
		pid_t child2 = fork();
		if (child2 < 0) {
			printf("fail");
		}
		else if (child1 == 0)
		{
			reader(semid, 2);
		}
		else
		{
			writer(semid);
		}
	}
	return 0;
}